﻿// SKNotes - a note taking and gathering tool
// Copyright (C) 2009  Stefan Kueng
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program.  If not, see <http://www.gnu.org/licenses/>.

namespace SKNotes.Utilities
{
    using System;
    using System.Collections.ObjectModel;
    using System.Runtime.Serialization;
    using System.Windows.Threading;

    [Serializable]
    public class BeginInvokeOC<T> : ObservableCollection<T>
    {
        [NonSerialized]
        private Dispatcher dispatcherUIThread;

        public BeginInvokeOC(Dispatcher dispatcher)
        {
            this.dispatcherUIThread = dispatcher;
        }

        private delegate void SetItemCallback(int index, T item);

        private delegate void RemoveItemCallback(int index);

        private delegate void ClearItemsCallback();

        private delegate void InsertItemCallback(int index, T item);

        private delegate void MoveItemCallback(int oldIndex, int newIndex);

        protected override void SetItem(int index, T item)
        {
            if (this.dispatcherUIThread.CheckAccess())
            {
                base.SetItem(index, item);
            }
            else
            {
                this.dispatcherUIThread.BeginInvoke(DispatcherPriority.Send, new SetItemCallback(this.SetItem), index, new object[] { item });
            }
        }

        protected override void RemoveItem(int index)
        {
            if (this.dispatcherUIThread.CheckAccess())
            {
                base.RemoveItem(index);
            }
            else
            {
                this.dispatcherUIThread.BeginInvoke(DispatcherPriority.Send, new RemoveItemCallback(this.RemoveItem), index);
            }
        }

        protected override void ClearItems()
        {
            if (this.dispatcherUIThread.CheckAccess())
            {
                base.ClearItems();
            }
            else
            {
                this.dispatcherUIThread.BeginInvoke(DispatcherPriority.Send, new ClearItemsCallback(this.ClearItems));
            }
        }

        protected override void InsertItem(int index, T item)
        {
            if (this.dispatcherUIThread.CheckAccess())
            {
                base.InsertItem(index, item);
            }
            else
            {
                this.dispatcherUIThread.BeginInvoke(DispatcherPriority.Send, new InsertItemCallback(this.InsertItem), index, new object[] { item });
            }
        }

        protected override void MoveItem(int oldIndex, int newIndex)
        {
            if (this.dispatcherUIThread.CheckAccess())
            {
                base.MoveItem(oldIndex, newIndex);
            }
            else
            {
                this.dispatcherUIThread.BeginInvoke(DispatcherPriority.Send, new MoveItemCallback(this.MoveItem), oldIndex, new object[] { newIndex });
            }
        }

        [OnDeserialized]
        private void OnDeserialized(StreamingContext context)
        {
            this.dispatcherUIThread = App.Current.Dispatcher;
        }
    }
}
